﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI.ETL.Domain.Services
{
    public class AppExtractService
    {
        public PagedList<Views.VAppExtractRecord> GetRecordPagedList(Guid appId, DateTime beginTime, DateTime endTime, int start, int limit)
        {
            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Views.VAppExtractRecord> aerRep = new EntityRepository<Views.VAppExtractRecord>(dbContext);

                List<Views.VAppExtractRecord> list = aerRep.Query(p => p.AppId == appId && p.CreatedTime >= beginTime && p.CreatedTime <= endTime).OrderBy(p => p.CreatedTime).Take(limit).Skip(start).ToList();

                int total = aerRep.Count(p => p.AppId == appId && p.CreatedTime >= beginTime && p.CreatedTime <= endTime);

                return new PagedList<Views.VAppExtractRecord>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), start, limit, total, list);
            }
        }

        public ServiceResult<Entities.EAppExtractRecord> CreateOrUpdate(Guid appId,
            Guid batchId, 
            Guid dataServiceType, 
            Guid dataSource,
            int dataCount,
            Guid[] passData,
            Guid[] unpassData)
        {
            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Entities.EAppExtractRecord> aerRep = new EntityRepository<Entities.EAppExtractRecord>(dbContext);
                Entities.EAppExtractRecord eRecord = aerRep.Get(p => p.AppId == appId && p.BatchId == batchId);
                
                int extractedCount = 0;
                int rejectedCount = 0;

                if(passData!=null)
                {
                    extractedCount = passData.Length;
                }

                if(unpassData!=null)
                {
                    rejectedCount = unpassData.Length;
                }

                if(eRecord ==null)
                {
                    #region created
                    eRecord = new Entities.EAppExtractRecord();
                    eRecord.Id = Guid.NewGuid();
                    eRecord.AppId = appId;
                    eRecord.BatchId = batchId;
                    eRecord.CreatedTime = DateTime.Now;
                    eRecord.DataServiceType = dataServiceType;
                    if (dataServiceType == DEF.DataServiceTypeId.DataService)
                    {
                        eRecord.DataServiceText = "DataService";
                        EntityRepository<Entities.EPubDataSource> pdsRep = new EntityRepository<Entities.EPubDataSource>(dbContext);
                        Entities.EPubDataSource ePDS = pdsRep.Get(p => p.Id == dataSource);
                        if(ePDS!=null)
                        {
                            eRecord.DataSourceType = ePDS.Type;
                            eRecord.DataSourceText = ePDS.Name;
                        }
                        eRecord.DataSource = dataSource;
                    }
                    else if (dataServiceType == DEF.DataServiceTypeId.RawData)
                    {
                        eRecord.DataServiceText = "RawDataService";
                        eRecord.DataSource = dataSource;
                        EntityRepository<Entities.EDtTable> dtRep = new EntityRepository<Entities.EDtTable>(dbContext);
                        Entities.EDtTable eDtTable = dtRep.Get(p => p.Id == dataSource);
                        if(eDtTable!=null)
                        {
                            eRecord.DataSourceText = eDtTable.Name;
                        }
                        else
                        {
                            eRecord.DataSourceText = "unknown";
                        }
                        eRecord.DataSourceType = DEF.RawDataService.DataTable;
                    }
                    else
                    {
                        eRecord.DataServiceText = "Unknown";
                        eRecord.DataSource = dataSource;
                        eRecord.DataSourceType = DEF.RawDataService.DataTable;
                    }
                    eRecord.DataCount = dataCount;
                    eRecord.ExtractedCount = extractedCount;
                    eRecord.RejectedCount = rejectedCount;
                    aerRep.Create(eRecord);
                    #endregion
                }
                else
                {
                    #region update
                    eRecord.ExtractedCount += extractedCount;
                    eRecord.RejectedCount += rejectedCount;
                    aerRep.Update(eRecord);
                    #endregion
                }

                CreateReceiveAndRejectRecord(dbContext,
                    appId,
                    batchId,
                    eRecord.Id,
                    dataServiceType,
                    dataSource,
                    passData,
                    unpassData);

                try
                {
                    dbContext.SaveChanges();
                    return new ServiceResult<Entities.EAppExtractRecord>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), eRecord);
                }
                catch(Exception ex)
                {
                    Logger.ErrorToTag(Library.LogTAG, string.Format("外部程序:{0}提取数据服务:{1}的数据源:{2}出错,ex:{3}", appId, dataServiceType, dataSource, ex));
                    return new ServiceResult<Entities.EAppExtractRecord>(false, ErrorCode.COM_Exception, ErrorCode.String(ErrorCode.COM_Exception));
                }
            }
        }

        private void CreateReceiveAndRejectRecord(EtlDbContext dbContext,
            Guid appId,
            Guid batchId,
            Guid extractRecordId,
            Guid dataServiceType,
            Guid dataSourceId,
            Guid[] passData,
            Guid[] unpassData)
        {
            EntityRepository<Entities.EAppExtractReceiveRecord> rcRep = new EntityRepository<Entities.EAppExtractReceiveRecord>(dbContext);
            EntityRepository<Entities.EAppExtractRejectRecord> rjRep = new EntityRepository<Entities.EAppExtractRejectRecord>(dbContext);

            if(passData!=null)
            {
                for (int index = 0; index < passData.Length; index++)
                {
                    Entities.EAppExtractReceiveRecord record = new Entities.EAppExtractReceiveRecord();
                    record.Id = Guid.NewGuid();
                    record.AppExtractRecordId = extractRecordId;
                    record.AppId = appId;
                    record.BatchId = batchId;
                    record.DataId = passData[index];
                    record.DataServiceType = dataServiceType;
                    record.DataSourceId = dataSourceId;
                    rcRep.Create(record);
                }
            }

            if(unpassData!=null)
            {
                for (int index = 0; index < unpassData.Length; index++)
                {
                    Entities.EAppExtractRejectRecord record = new Entities.EAppExtractRejectRecord();
                    record.Id = Guid.NewGuid();
                    record.AppExtractRecordId = extractRecordId;
                    record.AppId = appId;
                    record.BatchId = batchId;
                    record.DataId = unpassData[index];
                    record.DataServiceType = dataServiceType;
                    record.DataSourceId = dataSourceId;
                    rjRep.Create(record);
                }
            }
        }

        public ServiceResult<Models.MDtTableData> GetRejectedDataList(Guid appId, Guid recordId, Guid serviceType, Guid sourceId, int start, int limit, out int total)
        {
            total = 0;

            if (serviceType != DEF.DataServiceTypeId.RawData)
            {
                return new ServiceResult<Models.MDtTableData>(false, ErrorCode.COM_InvalidParameter, ErrorCode.String(ErrorCode.COM_InvalidParameter));
            }

            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Entities.EAppAuthorization> aaRep = new EntityRepository<Entities.EAppAuthorization>(dbContext);
                Entities.EAppAuthorization eAppAuthorization = aaRep.Get(p => p.AppId == appId);
                if (eAppAuthorization == null)
                {
                    return new ServiceResult<Models.MDtTableData>(false, ErrorCode.AppNotAuthorizated, ErrorCode.String(ErrorCode.AppNotAuthorizated));
                }

                EntityRepository<Entities.EDtTable> dtRep = new EntityRepository<Entities.EDtTable>(dbContext);
                Entities.EDtTable eTable = dtRep.Get(p => p.Id == sourceId);
                if (eTable == null)
                {
                    return new ServiceResult<Models.MDtTableData>(false, ErrorCode.COM_OBJNotExist, ErrorCode.String(ErrorCode.COM_OBJNotExist));
                }

                EntityRepository<Entities.EDtTableColumn> dtcRep = new EntityRepository<Entities.EDtTableColumn>(dbContext);
                List<Entities.EDtTableColumn> vDtColumns = dtcRep.GetList(p => p.DtTableId == eTable.Id);

                List<string> columns = new List<string>();
                for (int index = 0; index < vDtColumns.Count; index++)
                {
                    Entities.EDtTableColumn vDtColumn = vDtColumns[index];
                    columns.Add(vDtColumn.Name);
                }

                System.Data.DataTable dataTable = CPPEI.ETL.Domain.Util.DtTableUtil.GetAppExtractRejectedDataFromTable(dbContext,
                    eTable.ActualName,
                    columns,
                    string.Format("{0} in (select DataId from [ETL_AppExtractRejectRecord] where DataSourceId='{1}' and appid='{2}' and AppExtractRecordId='{3}')",
                        DEF.DtTableColumns.SYSCOL_Id,
                        sourceId,
                        appId,
                        recordId),
                        start, limit,
                        out total);

                Models.MDtTableData data = new Models.MDtTableData(start, limit, total, dataTable);
                return new ServiceResult<Models.MDtTableData>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), data);
            }
        }

        /// <summary>
        /// 获取被拒绝的数据对应的任务的批次列表
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="recordId"></param>
        /// <param name="serviceType"></param>
        /// <param name="sourceId"></param>
        /// <param name="start"></param>
        /// <param name="limit"></param>
        /// <param name="total"></param>
        /// <returns></returns>
        public ListResult<Views.VBatchDetail> GetReexecuteBatchList(Guid appId, Guid recordId, Guid serviceType, Guid sourceId)
        {
            if (serviceType != DEF.DataServiceTypeId.RawData)
            {
                return new ListResult<Views.VBatchDetail>(false, ErrorCode.COM_InvalidParameter, ErrorCode.String(ErrorCode.COM_InvalidParameter));
            }

            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Entities.EAppAuthorization> aaRep = new EntityRepository<Entities.EAppAuthorization>(dbContext);
                Entities.EAppAuthorization eAppAuthorization = aaRep.Get(p => p.AppId == appId);
                if (eAppAuthorization == null)
                {
                    return new ListResult<Views.VBatchDetail>(false, ErrorCode.AppNotAuthorizated, ErrorCode.String(ErrorCode.AppNotAuthorizated));
                }

                EntityRepository<Entities.EDtTable> dtRep = new EntityRepository<Entities.EDtTable>(dbContext);
                Entities.EDtTable eTable = dtRep.Get(p => p.Id == sourceId);
                if (eTable == null)
                {
                    return new ListResult<Views.VBatchDetail>(false, ErrorCode.COM_OBJNotExist, ErrorCode.String(ErrorCode.COM_OBJNotExist));
                }
                System.Data.DataTable dataTable = CPPEI.ETL.Domain.Util.DtTableUtil.SelectFromTable(dbContext,
                    eTable.ActualName,
                    string.Format("distinct {0}", DEF.DtTableColumns.SYSCOL_BatchId),
                    string.Format("{0} in (select DataId from [ETL_AppExtractRejectRecord] where DataSourceId='{1}' and appid='{2}' and AppExtractRecordId='{3}')",
                        DEF.DtTableColumns.SYSCOL_Id,
                        sourceId,
                        appId,
                        recordId));

                List<Views.VBatchDetail> batchDetailList = new List<Views.VBatchDetail>();
                EntityRepository<Entities.EBatch> bRep = new EntityRepository<Entities.EBatch>(dbContext);
                EntityRepository<Entities.EBatchParameter> tpRep = new EntityRepository<Entities.EBatchParameter>(dbContext);
                EntityRepository<Entities.EDtSourceParameter> dspRep = new EntityRepository<Entities.EDtSourceParameter>(dbContext);
                for (int index = 0; index < dataTable.Rows.Count; index++)
                {
                    Guid batchId = new Guid(Convert.ToString(dataTable.Rows[index][DEF.DtTableColumns.SYSCOL_BatchId]));

                    Entities.EBatch eBatch = bRep.Get(p => p.Id == batchId);

                    Views.VBatchDetail detail = new Views.VBatchDetail();
                    detail.Batch = eBatch;

                    detail.Parameters = tpRep.Query(p => p.BatchId == batchId).OrderBy(p => p.Index).ToList();
                    detail.SourceParameters = dspRep.Query(p => p.DtSourceId == eBatch.DtSourceId).OrderBy(p => p.Index).ToList();
                    batchDetailList.Add(detail);
                }

                return new ListResult<Views.VBatchDetail>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), batchDetailList);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="batchId">这个数据采集时的批次号</param>
        /// <param name="serviceType"></param>
        /// <param name="source"></param>
        /// <param name="dataId"></param>
        /// <returns></returns>
        public ServiceResult<Views.VRawDataDetail> GetDataDetail(Guid batchId, Guid serviceType, Guid source, Guid dataId)
        {
            if (serviceType != DEF.DataServiceTypeId.RawData)
            {
                return new ServiceResult<Views.VRawDataDetail>(false, ErrorCode.Service_IsNotRDS, ErrorCode.String(ErrorCode.Service_IsNotRDS));
            }

            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Entities.EDtTable> dtRep = new EntityRepository<Entities.EDtTable>(dbContext);
                Entities.EDtTable eTable = dtRep.Get(p => p.Id == source);
                if (eTable == null)
                {
                    return new ServiceResult<Views.VRawDataDetail>(false, ErrorCode.COM_OBJNotExist, ErrorCode.String(ErrorCode.COM_OBJNotExist));
                }

                EntityRepository<Entities.EDtTableColumn> dtcRep = new EntityRepository<Entities.EDtTableColumn>(dbContext);
                List<Entities.EDtTableColumn> vDtColumns = dtcRep.GetList(p => p.DtTableId == eTable.Id);

                EntityRepository<Entities.EBatch> bRep = new EntityRepository<Entities.EBatch>(dbContext);
                Entities.EBatch eBatch = bRep.Get(p => p.Id == batchId);

                EntityRepository<Entities.DtSource> dSourceRep = new EntityRepository<Entities.DtSource>(dbContext);
                Entities.DtSource dataSource = dSourceRep.Get(p => p.Id == eBatch.DtSourceId);

                EntityRepository<Entities.DtSer> dSerRep = new EntityRepository<Entities.DtSer>(dbContext);
                Entities.DtSer dataService = dSerRep.Get(p => p.Id == eBatch.DtSerId);

                EntityRepository<Views.VDtSourceDataIdentity> dsdiRep = new EntityRepository<Views.VDtSourceDataIdentity>(dbContext);
                List<Views.VDtSourceDataIdentity> vDataIdentities = dsdiRep.Query(p => p.DtSerId == eBatch.DtSerId 
                    && p.DtSourceId == eBatch.DtSourceId).OrderBy(p => p.Index).ToList();

                List<string> columns = new List<string>();
                for (int index = 0; index < vDtColumns.Count; index++)
                {
                    Entities.EDtTableColumn vDtColumn = vDtColumns[index];
                    columns.Add(vDtColumn.Name);
                }

                string sqlWhere = string.Format("{0} = '{1}'", DEF.DtTableColumns.SYSCOL_Id, dataId);
                System.Data.DataTable dataTable = CPPEI.ETL.Domain.Util.DtTableUtil.GetDataFromTableWithWhere(dbContext,
                    eTable.ActualName,
                    columns,
                    sqlWhere);

                StringBuilder dataIdentity = new StringBuilder();
                for (int index = 0; index < vDataIdentities.Count; index++)
                {
                    string diValue = Convert.ToString(dataTable.Rows[0][vDataIdentities[index].DtTableColumnName]);
                    if(index ==0)
                    {
                        dataIdentity.Append(diValue);
                    }
                    else
                    {
                        dataIdentity.AppendFormat(",{0}", diValue);
                    }
                }

                EntityRepository<Views.VBatchParameter> epRep = new EntityRepository<Views.VBatchParameter>(dbContext);

                Views.VRawDataDetail detail = new Views.VRawDataDetail();
                detail.DataId = dataId;
                detail.BatchId = batchId;
                detail.DataIdentity = dataIdentity.ToString();
                detail.DtServiceId = dataService.Id;
                detail.DtServiceText = dataService.Name;
                detail.DtSourceId = dataSource.Id;
                detail.DtSourceText = dataSource.Name;
                detail.ServiceText = "RawDataService";
                detail.ServiceType = serviceType;
                detail.Source = source;
                detail.SourceText = eTable.Name;
                detail.CreatedTime = eBatch.CreatedTime;
                detail.Parameters = epRep.GetList(p => p.BatchId == batchId);

                return new ServiceResult<Views.VRawDataDetail>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), detail);
            }
        }

        public ServiceResult<Views.VDataBatchListDetail> GetDataBatchListDetail(Guid serviceType, Guid source,  Guid batchId, string dataIdentity, int start, int limit)
        {
            if (serviceType != DEF.DataServiceTypeId.RawData)
            {
                return new ServiceResult<Views.VDataBatchListDetail>(false, ErrorCode.Service_IsNotRDS, ErrorCode.String(ErrorCode.Service_IsNotRDS));
            }

            using (EtlDbContext dbContext = new EtlDbContext())
            {
                EntityRepository<Entities.EDtTable> dtRep = new EntityRepository<Entities.EDtTable>(dbContext);
                Entities.EDtTable eTable = dtRep.Get(p => p.Id == source);
                if (eTable == null)
                {
                    return new ServiceResult<Views.VDataBatchListDetail>(false, ErrorCode.COM_OBJNotExist, ErrorCode.String(ErrorCode.COM_OBJNotExist));
                }

                EntityRepository<Entities.EBatch> bRep = new EntityRepository<Entities.EBatch>(dbContext);
                Entities.EBatch eBatch = bRep.Get(p => p.Id == batchId);

                EntityRepository<Entities.DtSource> dSourceRep = new EntityRepository<Entities.DtSource>(dbContext);
                Entities.DtSource dataSource = dSourceRep.Get(p => p.Id == eBatch.DtSourceId);

                EntityRepository<Entities.DtSer> dSerRep = new EntityRepository<Entities.DtSer>(dbContext);
                Entities.DtSer dataService = dSerRep.Get(p => p.Id == eBatch.DtSerId);


               ServiceResult<Models.MDtTableData> serResult = GetBatchDataList(dbContext, eTable, dataService, dataSource, dataIdentity, start, limit);
                if(!serResult.IsSuccess)
                {
                    return new ServiceResult<Views.VDataBatchListDetail>(false, ErrorCode.COM_OBJNotExist, ErrorCode.String(ErrorCode.COM_OBJNotExist));
                }

                Views.VDataBatchListDetail detail = new Views.VDataBatchListDetail();
                detail.DtServiceId = dataService.Id;
                detail.DtServiceText = dataService.Name;
                detail.DtSourceId = dataSource.Id;
                detail.DtSourceText = dataSource.Name;
                detail.ServiceText = "RawDataService";
                detail.ServiceType = serviceType;
                detail.Source = source;
                detail.SourceText = eTable.Name;
                detail.DtTableData = serResult.Data;
                return new ServiceResult<Views.VDataBatchListDetail>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), detail);
            }
        }

        private ServiceResult<Models.MDtTableData> GetBatchDataList(EtlDbContext dbContext, Entities.EDtTable dataTable,
            Entities.DtSer dataService,
            Entities.DtSource dataSource,
            string dataIdentity, int start, int limit)
        {
            int total = 0;

            EntityRepository<Views.VDtSourceDataIdentity> dsdiRep = new EntityRepository<Views.VDtSourceDataIdentity>(dbContext);
            List<Views.VDtSourceDataIdentity> vDataIdentities = dsdiRep.Query(p => p.DtSerId == dataService.Id && p.DtSourceId == dataSource.Id).OrderBy(p => p.Index).ToList();

            string[] dataIdentityArr = dataIdentity.Split(new char[] { ',' });
            StringBuilder sqlWhere = new StringBuilder();
            for (int index = 0; index < vDataIdentities.Count; index++)
            {
                if (index == 0)
                {
                    sqlWhere.AppendFormat("[{0}] = '{1}'", vDataIdentities[index].DtTableColumnName, dataIdentityArr[index]);
                }
                else
                {
                    sqlWhere.AppendFormat(" and [{0}] = '{1}'", vDataIdentities[index].DtTableColumnName, dataIdentityArr[index]);
                }
            }

            EntityRepository<Entities.EDtTableColumn> dtcRep = new EntityRepository<Entities.EDtTableColumn>(dbContext);
            List<Entities.EDtTableColumn> vDtColumns = dtcRep.GetList(p => p.DtTableId == dataTable.Id);


            List<string> columns = new List<string>();
            for (int index = 0; index < vDtColumns.Count; index++)
            {
                Entities.EDtTableColumn vDtColumn = vDtColumns[index];
                columns.Add(vDtColumn.Name);
            }

            System.Data.DataTable data = CPPEI.ETL.Domain.Util.DtTableUtil.GetPagedDataFromTableWithWhere(dbContext,
                dataTable.ActualName,
                columns,
                sqlWhere.ToString(),
                start,
                limit,
                    out total);

            Models.MDtTableData mData = new Models.MDtTableData(start, limit, total, data);
            return new ServiceResult<Models.MDtTableData>(true, ErrorCode.COM_NoError, ErrorCode.String(ErrorCode.COM_NoError), mData);
        }
    }
}
